#include <random>
#include <chrono>
#include <iostream>

#include "utilities.h"
#include "FireworkManager.h"
#include "DataSingleton.h"

#include "VsgManager.h"

struct VsgManagerData {
	FireworkManager manager;
};

void VsgManager::init()
{
	initViewer();
	initWindow();
	initData();
	initScene();
	initCamera();
}

void VsgManager::run()
{
	vsg::time_point timeStamp = vsg::clock::now();
	while (m_viewer->advanceToNextFrame())
	{
		// pass any events into EventHandlers assigned to the Viewer
		m_viewer->handleEvents();
		auto timeNow = vsg::clock::now();
		std::chrono::nanoseconds delt = timeNow - timeStamp;
		timeStamp = timeNow;
		update(delt);

		m_viewer->update();

		m_viewer->recordAndSubmit();

		m_viewer->present();
	}
}

void VsgManager::update(std::chrono::nanoseconds delt)
{
	m_data->manager.update(delt);
}

void VsgManager::initWindow()
{
	std::cout << "initWindow...start" << std::endl;
	auto windowTraits = vsg::WindowTraits::create();
	windowTraits->fullscreen = true;
	m_window = vsg::Window::create(windowTraits);
	m_window->clearColor() = VkClearColorValue{ {0,0,0,1} };
	m_viewer->addWindow(m_window);
	m_viewer->addEventHandler(vsg::CloseHandler::create(m_viewer));
	std::cout << "initWindow...done" << std::endl;
}

void VsgManager::initCamera()
{
	std::cout << "initCamera...start" << std::endl;
	vsg::dbox sceneBox;
	double weight = 50;
	double length = 50;
	double a = -9.8;
	double v0 = 10;
	double t = -v0 / a;
	double height = v0 * t + 0.5 * a * pow(t, 2.0);
	double low_height = height * 0.5;
	sceneBox.add(-weight, -length, height);
	sceneBox.add(-weight, length, height);
	sceneBox.add(weight, length, height);
	sceneBox.add(weight, length, height);
	sceneBox.add(-weight, -length, -low_height);
	sceneBox.add(-weight, length, -low_height);
	sceneBox.add(weight, length, -low_height);
	sceneBox.add(weight, length, -low_height);
	vsg::dvec3 centre = (sceneBox.min + sceneBox.max) * 0.5;
	double radius = vsg::length(sceneBox.max - sceneBox.min) * 0.5;
	vsg::ref_ptr<vsg::LookAt> lookAt;
	vsg::dvec3 eye{ -50., -50., 0.0 };
	vsg::dvec3 center = { 120.,50., 120. };
	vsg::dvec3 up = vsg::dvec3(0.0, 0.0, 1.0);
	lookAt = vsg::LookAt::create(eye, center, up);

	double nearFarRatio = 0.001;
	auto perspective = vsg::Perspective::create(70.0, static_cast<double>(m_window->extent2D().width) / static_cast<double>(m_window->extent2D().height), nearFarRatio, 1000);

	m_camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(m_window->extent2D()));

	m_viewer->addEventHandler(vsg::Trackball::create(m_camera));

	auto commandGraph = vsg::createCommandGraphForView(m_window, m_camera, m_scene);
	m_viewer->assignRecordAndSubmitTaskAndPresentation({ commandGraph });

	m_viewer->compile();

	std::cout << "initCamera...done" << std::endl;
}

void VsgManager::initViewer()
{
	std::cout << "initViewer...start" << std::endl;
	m_viewer = vsg::Viewer::create();
	std::cout << "initViewer...done" << std::endl;
}

void VsgManager::initScene()
{
	std::cout << "initScene...start" << std::endl;
	m_scene = vsg::Group::create();
	m_scene->addChild(m_data->manager.getNode());
	std::cout << "initScene...done" << std::endl;
}

void VsgManager::initData()
{
	m_data = new VsgManagerData();
	m_data->manager.setFireworkCount(8);
	DataSingleton::instance()->m_device = m_window->getOrCreateDevice();
}


